;; -*- emacs-lisp -*-
;; Last modified: <Saturday 31 January 2009, 16:51:02 EST>


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;               General Configuration                            ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; adding load path
(add-to-list 'load-path "~/.emacs.d")
(add-to-list 'load-path "~/.emacs.d/Lisp")
(add-to-list 'load-path "~/.emacs.d/Lisp/eieio")
(add-to-list 'load-path "~/.emacs.d/images")

(if (not (file-exists-p "~/.emacs.d/my.emacs.elc"))
	(if (y-or-n-p-with-timeout "First Run! Byte compile directory? (default y in 10s) " 10 t)
		(progn
		  (byte-compile-file "~/.emacs.d/my.emacs")
		  (byte-recompile-directory "~/.emacs.d/" 0))))

;; appearance of EMACS
(set-face-attribute 'fringe nil
					:foreground "lawngreen"
					:background "SteelBlue4")
(custom-set-variables
  ;; custom-set-variables was added by Custom.
  ;; If you edit it by hand, you could mess it up, so be careful.
  ;; Your init file should contain only one such instance.
  ;; If there is more than one, they won't work right.
 '(adaptive-fill-first-line-regexp "^\\* *$")
 '(adaptive-fill-regexp "[ 	]+\\|[ 	]*\\([0-9]+\\.\\|\\*+\\)[ 	]*")
 '(column-number-mode t)
 '(cua-enable-cua-keys nil)
 '(cua-keep-region-after-copy t)
 '(cua-mode t nil (cua-base))
 '(cursor-type (quote bar) t)
 '(custom-buffer-style (quote brackets))
 '(default-major-mode (quote text-mode))
 '(default-tab-width 4 t)
 '(dired-recursive-copies (quote top))
 '(dired-recursive-deletes (quote top))
 '(display-time-format "%x %A %R")
 '(display-time-mode t)
 '(even-window-heights nil)
 '(fill-column 80)
 '(frame-title-format (quote ((buffer-file-name "%f" (or dired-directory "%b")) " - GNU Emacs")) t)
 '(icon-title-format (quote ((buffer-file-name "%f" (or dired-directory "%b")) " - GNU Emacs")) t)
 '(global-auto-revert-mode t)
 '(global-font-lock-mode t)
 '(global-hl-line-mode t)
 '(ido-enable-flex-matching t)
 '(ido-everywhere t)
 '(ido-mode t nil (ido))
 '(inhibit-startup-screen t)
 '(ispell-local-dictionary "american" t)
 '(ispell-program-name "aspell" t)
 '(kill-whole-line t)
 '(mouse-avoidance-mode (quote animate) nil (avoid))
 '(mouse-yank-at-point t)
 '(org-agenda-files nil)
 '(require-final-newline t)
 '(safe-local-variable-values (quote ((TeX-master . t))))
 '(sentence-end "\\([£¬¡¢¡££¡£¿]\\|¡­¡­\\|[.?!][]\"')}]*\\($\\|[ 	]\\)\\)[ 	]*")
 '(sentence-end-double-space nil)
 '(show-paren-mode t)
 '(show-paren-style (quote expression))
 '(track-eol t)
 '(tramp-default-method "ssh")
 '(transient-mark-mode t)
 '(uniquify-buffer-name-style (quote forward) nil (uniquify))
 '(user-full-name "Zengyin Zhang")
 '(user-mail-address "zhangzyin@gmail.com")
 '(viper-mode t)
 '(visible-bell t)
 '(w32-lwindow-modifier (quote super) t)
 '(time-stamp-line-limit 8)
 '(time-stamp-start "Last modified: <")
 '(time-stamp-end ">")
 '(time-stamp-format "%:a %02d %:b %:y, %02H:%02M:%02S %Z"))
(custom-set-faces
  ;; custom-set-faces was added by Custom.
  ;; If you edit it by hand, you could mess it up, so be careful.
  ;; Your init file should contain only one such instance.
  ;; If there is more than one, they won't work right.
 '(default ((t (:inherit nil :stipple nil :background "lightblue" :foreground "#000000" :inverse-video nil :box nil :strike-through nil :overline nil :underline nil :slant normal :weight normal :height 100 :width normal :foundry "unknown" )))))

(when
 (eq (frame-parameter (selected-frame) 'background-mode) 'light)
	 (if (memq window-system '(x w32))
		 (progn
		   (set-face-attribute 'font-lock-string-face nil
							   :foreground "magenta"
							   :italic t)
		   
		   ;(modify-all-frames-parameters '((background-color . "lightblue")))
		   ;(add-to-list 'default-frame-alist '(background-color . "lightblue"))
		   (set-background-color "#B7E8BD")
		   ;(add-to-list 'window-system-default-frame-alist '((background-color . "#B7E8BD")))
		   ;(modify-frame-parameters (selected-frame) '((background-color . "#B7E8BD")))
		   (set-face-attribute 'highlight nil
							   :background "deepskyblue"))))


(fset 'yes-or-no-p 'y-or-n-p)

(when (memq window-system '(x w32))
  (custom-set-variables
   '(w32-lwindow-modifier (quote super) t)))

;; (setq ascii-font
;; 	  "-outline-Consolas-normal-r-normal-normal-12-97-96-96-c-*-iso8859-1")
;; (setq chinese-font
;;       "-outline-Î¢ÈíÑÅºÚ-normal-r-normal-normal-14-*-96-96-p-*-iso10646-1")

(mapc (lambda (pair) (if (boundp (car pair))
						 (set (car pair) (cdr pair))))
      '((mode-line-in-non-selected-windows  . t)
		(default-indicate-buffer-boundaries . 'left)
		(overflow-newline-into-fringe       . t)))

(add-hook 'write-file-hooks 'time-stamp)

;; enable tabbar
(require 'tabbar)
(setq tabbar-buffer-groups-function 'tabbar-buffer-ignore-groups)
(setq tabbar-speedkey-use t)
(setq tabbar-speedkey-prefix (kbd "C-1"))
(tabbar-mode 1)
(add-hook 'ibuffer-hook 'tabbar-local-mode)
(add-hook 'Info-mode-hook 'tabbar-local-mode)

;; line number mode
(if (require 'linum nil t)
	(progn
	  (set-face-attribute 'linum nil
						  :weight 'bold
						  :foreground "green")
	  (when (eq (frame-parameter (selected-frame) 'background-mode) 'light)
		(if (memq window-system '(x w32))
			(set-face-attribute 'linum nil
								:background "SteelBlue4")
		  (set-face-attribute 'linum nil
							  :background "black")))))

;; spell check
(setq-default ispell-program-name "aspell")
(setq-default ispell-local-dictionary "american")
(global-set-key [(f8)] 'ispell-complete-word)

;; set backup behavior
(require 'backup-dir)
(setq make-backup-files t
	  version-control t
	  kept-old-versions 1
	  kept-new-versions 10
	  delete-old-versions t
	  bkup-backup-directory-info '((t "~/.emacs.d/.backups/" ok-createfull-path)))

;; svn-mode
(require 'psvn)

;; git-mode     for Debian Distribution
(when (memq system-type '(gnu gnu/linux)) ; only for linux system
  ;;(setq load-path (cons (expand-file-name "/usr/share/doc/git-core/contrib/emacs") load-path))
  (require 'vc-git)
  (when (featurep 'vc-git) (add-to-list 'vc-handled-backends 'git))
  (require 'git)
  (autoload 'git-blame-mode "git-blame"
	"Minor mode for incremental blame for Git." t)

  (defun git-run-process-region (buffer start end program args)
	"Run a git process with a buffer region as input."
	(let ((output-buffer (current-buffer))
		  (dir default-directory))
	  (with-current-buffer buffer
		(cd dir)
		(apply #'git-run-process-region-eip start end program
			   nil (list output-buffer nil) nil args))))

  (defun git-run-process-region-eip (start end program &optional delete buffer display &rest args)
	(let ((fh (find-file-name-handler default-directory 'tmp)))
	  (unwind-protect
		  (if fh
			  (progn
				(let ((tfn (make-temp-file "emacs")) ret)
				  (write-region start end tfn)
				  (setq ret (apply fh 'process-file program tfn buffer display args))
				  (when tfn (delete-file tfn))
				  ret)
				)
			(apply #'call-process-region start end program delete buffer display args)))))
  )
;; kill-ring
(when (require 'browse-kill-ring nil t)
  (browse-kill-ring-default-keybindings)
  (setq kill-ring-max 200))

;; VIPER mode settings
(setq viper-custom-file-name "~/.emacs.d/my.viper")
(require 'viper)

;; cua mode
(dolist (cmd
		 '(my-beginning-of-line Screen-lines-end-of-line
								beginning-of-line end-of-line))
  (put cmd 'CUA 'move))		; enable shift + home&end action as move marking action
(require 'eip_cua_drag_ex)
(when (featurep 'viper)
  (progn
	(put 'viper-beginning-of-line 'CUA 'move)
	(define-key cua--region-keymap [remap viper-delete-char]
	  'cua-delete-region)
	(define-key cua--region-keymap [remap
									viper-delete-backward-word]
	  'cua-cut-region)
	(define-key cua--region-keymap [remap
									viper-del-backward-char-in-insert]
	  'cua-delete-region)
	))

;; maximize window
(require 'maxframe)
(add-hook 'window-setup-hook 'maximize-frame t)

;; truncate-line
(defun eip-toggle-truncate-line ()
  (interactive)
  (goto-char (line-beginning-position))
  (save-excursion
    (setq truncate-lines (not truncate-lines))
    (force-window-update)))

(tool-bar-add-item "widen" 'eip-toggle-truncate-line 'eip-toggle-truncate-line
				   :help "Toggle Truncate Line"
				   :button (cons :toggle '(and (boundp truncate-lines)
											   (not truncate-lines))))

;; redo
(require 'redo)


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;               Eiplor Stuff Configuration                       ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(require 'eip_utils)
(load "eip_func")
(load "eip_c_mod")
(load "eip_perl_mod")
(load "eip_misc")
(load "eip_tex_mod")
(load "eip_matlab_mod")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;               KEY Configuration                                ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(global-set-key [(control ?\.)] 'ska-point-to-register)   ; ÔÚÎÄµµÖÐ×ö±ê¼Ç
(global-set-key [(control ?\,)] 'ska-jump-to-register)    ; Ìøµ½±ê¼Ç
(global-set-key (kbd "C-a") 'mark-whole-buffer)           ; ±ê¼ÇÈ«ÎÄ
(global-set-key (kbd "C-c a") 'my-go-to-char)
(global-set-key (kbd "C-c k") 'browse-kill-ring)          ; ²é¿´¼ôÌù°å
(global-set-key (kbd "C-M-z") 'redo)					  ; undoºóredo
(global-set-key (kbd "M-/") 'hippie-expand)               ; ÖÇÄÜ²¹È«
(global-set-key (kbd "%") 'match-paren)                   ; À¨ºÅÆ¥Åä
(global-set-key (kbd "C-x C-b") 'ibuffer)                 ; ÁÐ±íÏÔÊ¾µ±Ç°ËùÓÐbuffer
(when (featurep 'linum) (global-set-key (kbd "C-c l") 'linum-mode))
(global-set-key [(tab)] 'my-indent-or-complete)			  ; Ëõ½øºÍ²¹È«
(global-set-key [(control meta down)] 'tabbar-backward-group)
(global-set-key [(control meta up)] 'tabbar-forward-group)
(global-set-key [(control meta left)] 'tabbar-backward)
(global-set-key [(control meta right)] 'tabbar-forward)
(global-set-key [(control tab)] 'tabbar-forward)          ; ÏÂÒ»±êÇ©Ò³
(global-set-key [(control shift tab)] 'tabbar-backward)   ; ÉÏÒ»±êÇ©Ò³
(global-set-key (kbd "<header-line> <double-mouse-1>") 'kill-this-buffer)     ; Ë«»÷±êÇ©Ò³,¹Ø±Õ¸Äbuffer
(cond ((eq window-system 'w32)
       (global-set-key (kbd "<header-line> <wheel-up>") 'tabbar-backward-keep-buffer)
       (global-set-key (kbd "<header-line> <wheel-down>") 'tabbar-forward-keep-buffer))
      ((eq window-system 'x)
       (global-set-key (kbd "<header-line> <mouse-4>") 'tabbar-backward-keep-buffer)
       (global-set-key (kbd "<header-line> <mouse-5>") 'tabbar-forward-keep-buffer)))

(global-set-key [(control f4)] 'kill-this-buffer)         ; ¹Ø±Õµ±Ç°buffer
(global-set-key (kbd "C-`") 'delete-other-windows)        ; È¥³ýÆäËû´°¿Ú,Ö»±£Áôµ±Ç°´°¿Ú
(global-set-key (kbd "C-e") 'eval-current-buffer)
(global-set-key [(super a)] 'list-bookmarks)
(global-set-key [(f9)] 'compile)
(global-set-key [(f12)] 'list-bookmarks)
;; moving to a line specified by a number
(global-set-key [(control g)] 'goto-line)                 ; Ìøµ½Ä³ÐÐ
;; move forward or backward block
(global-set-key [(meta left)] 'backward-sexp)
(global-set-key [(meta right)] 'forward-sexp)
;; my-beginning-of-line
(global-set-key [(home)] 'my-beginning-of-line)
;; set return to newline-and-indent
;;(global-set-key [(return)] 'newline-and-indent)
(global-set-key [(f1)] (lambda() 
						 (interactive) 
						 (let ((woman-topic-at-point t))
						   (woman))))
(global-set-key [(control backspace)] 'backward-kill-word)
(global-set-key [(control delete)] 'kill-word)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;               Org-Mode Configuration                           ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(when (require 'org nil t)
  (require 'org-mouse)
  (setq org-log-done t
		org-hide-leading-stars t)
  (set-face-attribute 'org-hide nil
					  :foreground (frame-parameter (selected-frame)
												   'background-color))
  (define-key org-mode-map "\C-cs" 'org-store-link)
  (define-key org-mode-map "\C-ca" 'org-agenda)
  (define-key org-mode-map "\C-co" 'org-agenda-open-link))

(maximize-frame)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;               Server-Mode Configuration                        ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(when (and (require 'server nil t)
		   (not (setq eip-exist-emacs-instance (server-running-p))))

  (define-key-after menu-bar-tools-menu [server-start]
    '("(Re)start Server" . server-start) t)

  ;; visit file in a new frame window
  (eip-make-hook-fn server-visit-hook
					(setq server-window (make-frame)))
  
  ;; automatically maximize new frame window
  (if (featurep 'maxframe)
      (eip-make-hook-fn server-switch-hook
						(maximize-frame)))
  
  (eip-make-hook-fn server-done-hook
					;; Has no effect if client called with --no-wait. Fair enough.
					;; Hence --no-wait. no longer used. Given that,
					;; C-x # will kill buffer if `server-kill-new-buffers' is non-nil.
					(delete-frame server-window)
					;; Without this line the frame gets recreated.
					(setq server-window nil))
  (server-start))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;               Desktop-Mode Configuration                        ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(when (and (require 'desktop nil t) (not eip-exist-emacs-instance))
  (set (if (boundp 'desktop-base-file-name) 'desktop-base-file-name
         'desktop-basefilename) "emacs.desktop")

  (setq desktop-missing-file-warning nil
        ;; Default includes tags table, which is annoying.
        desktop-globals-to-save '((file-name-history        . 10)
                                  (command-history          . 10)
                                  (extended-command-history . 10)
                                  (shell-command-history    . 10)
                                  (query-replace-history    . 10)
                                  (regexp-history           . 10)
                                  (minibuffer-history       . 10)
                                  (search-ring              . 10)
                                  (regexp-search-ring       . 10)
                                  (register-alist           . 10))
        desktop-buffers-not-to-save
        "\\(^TAGS\\|/VM/\\|/Gnus/\\|/bbdb/\\|^[a-zA-Z0-9@]+:\\)"
		desktop-files-not-to-save "//"
		desktop-dirname "~/.emacs.d/desktops")
  (add-to-list 'desktop-path '"~/.emacs.d/desktops")
  

  (desktop-save-mode t)
  
  ;; desktop-read kills any unmodified buffers not listed in desktop.
  ;; Hence prefer to retain some control over this.
  (and (file-exists-p
		(expand-file-name
		 (if (boundp 'desktop-base-file-name)
			 desktop-base-file-name
		   desktop-basefilename) desktop-dirname))
       ;; Crude test to see if specified file name on command line,
       ;; in which case probably don't want to load desktop.
       ;; Should really parse and check for options versus file-names.
       ;; Note this also covers the -f vm case.
       ;; (< (length command-line-args) 2)
       (if (y-or-n-p-with-timeout "Load Desktop? (default y in 10s) " 10 t) ()
		 (desktop-read)))

;;;   (add-hook 'eip-before-kill-emacs-hook
;;; 			(lambda ()
;;; 			  (desktop-save
;;; 			   (concat "~/.emacs.d/desktops"))))
										;(remove-hook 'kill-emacs-hook 'desktop-kill)
  

  (defun my-count-interesting-buffers ()
    "Return the current number of \"interesting\" buffers.
An interesting buffer: is visible; has a name not starting with \"*\"."
    (let ((n 0))
      (dolist (buff (buffer-list))
        (or (string-match "^[ *]" (buffer-name buff)) (setq n (1+ n))))
      n))

  (defvar my-desktop-nbuffers 5
    "Must be at least this many \"interesting\" buffers to auto-save desktop.
The function `my-count-interesting-buffers' is used.")

  (defvar my-desktop-auto-save-dir (file-name-as-directory
                                    (expand-file-name "desktops" "~/.emacs.d"))
    "Directory used by `my-desktop-auto-save'.")

  (defvar my-desktop-auto-save-interval 600
    "Interval in seconds before desktop is auto-saved.")

  (defvar my-desktop-auto-save-timer nil
    "Timer for `my-desktop-auto-save-mode'.")

  (defun my-desktop-auto-save ()
    "Save the current desktop to the directory `my-desktop-auto-save-dir'."
    (let ((dir my-desktop-auto-save-dir)
          ;; Prevent desktop-save setting global value.
          (desktop-dirname desktop-dirname)
          (desktop-base-file-name
           (format "desktop-%s-%s" (format-time-string "%Y_%m_%d") (emacs-pid)))
          (string "Saving desktop..."))
      (when (>= (my-count-interesting-buffers) my-desktop-nbuffers)
;;;        (message "%s" string)
        (or (file-exists-p dir) (make-directory dir))
        ;; Delete any existing desktops for this PID (eg from previous day).
        (mapc (lambda (file) (delete-file file))
              (file-expand-wildcards (expand-file-name
                                      (format "desktop-*-%s" (emacs-pid))
                                      dir)))
        (desktop-save dir)
        (if (get-buffer "*desktop*") (kill-buffer "*desktop*"))
;;;        (message "%s%s" string "done")
        )))

  (define-minor-mode my-desktop-auto-save-mode
    "Toggle periodic saving of the desktop.
With optional numeric argument ARG, activate saving only if ARG
is positive."
    :global t
    (if my-desktop-auto-save-mode
        (or my-desktop-auto-save-timer  ; already running?
            (setq my-desktop-auto-save-timer
                  (run-with-timer 0 my-desktop-auto-save-interval
                                  'my-desktop-auto-save)))
      (if (timerp my-desktop-auto-save-timer)
          (cancel-timer my-desktop-auto-save-timer))))


  ;; TODO do not bother with this when connecting over ssh.
  ;; Or when DISPLAY != $MYXPC?
  (my-desktop-auto-save-mode 1)


  (defun my-newest-file-in-directory (dir &optional match-regexp oldest)
    "Return the (base)name of the newest file in DIR.
File names must match optional regexp MATCH-REGEXP.  With
optional argument OLDEST, return instead the oldest.  Age is
based on modification time. Note that \".\" and \"..\" are
included by default."
    ;; d-f-a-a signals an error if we do not.
    (or (file-directory-p dir)
        (error "Directory `%s' not found" dir))
    (let ((flist (directory-files-and-attributes dir nil match-regexp t)))
      (or flist (error "No files in `%s' match \"%s\"" dir match-regexp))
      (setq flist (sort flist
                        (lambda (e1 e2)
                          (< (+ (* (car (nth 6 e1)) (expt 2 16))
                                (cadr (nth 6 e1)))
                             (+ (* (car (nth 6 e2)) (expt 2 16))
                                (cadr (nth 6 e2)))))))
      (if oldest (caar flist)
        (caar (last flist)))))


  (defun my-desktop-recover (file)
    "Recover the desktop from FILE."
    (interactive
     (let ((fname (my-newest-file-in-directory
                   my-desktop-auto-save-dir "^desktop")))
       (list (read-file-name "Desktop file: " my-desktop-auto-save-dir
                             (expand-file-name fname my-desktop-auto-save-dir)
                             t fname))))
    (let ((desktop-base-file-name (file-name-nondirectory file)))
      (desktop-read (file-name-directory file))))
  )

(defadvice save-buffers-kill-emacs (around before-kill-hook activate)
  "Run `eip-before-kill-emacs-hook' before save-buffers-kill-emacs."
  ;; This is so that an abortive exit does not mess up our session.
  ;; Also quite nice since it means we do not get prompted to save
  ;; files etc unless we have really decided to exit emacs.
  ;; But maybe we will change our mind if we know files have to be saved?
  (when (yes-or-no-p "Really exit Emacs? ")
    (run-hooks 'eip-before-kill-emacs-hook)
    (setq confirm-kill-emacs nil)       ; no need to ask twice
    ad-do-it))

